﻿using System;
using System.Collections.Generic;
using System.Text;
using RegionInterface;
using Common;
using UnityEngine;

public class MonsterHandle : IMonsterHandle
{
    private float findRadius = 10.0f;//警戒半径
    private float attackRadius = 3;//攻击半径
    private float attackInterval = 1.5f;//攻击间隔
    private float walkSpeed = 5;//移动速度

    public MonsterModule Module;
    public Transform Root;
    public GameObject WeaponObject;
    public GameObject ClothesObject;
    public CharacterController moveController;
    public  MonsterAnimationSet AnimationSet;
    public ActionParameter[] ActionList = null;
    public bool Live = false;
    public MonsterAction CurrentAction;

    private const float flickerWait = 0.1f;
    private float deadDuration = 0;
    private const byte flickerCount = 20;
    private byte flickerTotal = 0;

    private IAvatarHandle targetAvatar;
    private bool goBack = false;
    private float lastZ = 0;
    private Vector3 leftAngle = new Vector3(0, 180, 0);
    private Vector3 rightAngle = Vector3.zero;
    private Vector3 speed = Vector3.zero;
    private Vector3 tSpeed = Vector3.zero;
    private Vector3 defaultPos = Vector3.zero;
    private float tFindRadius = 0;
    private float distance = 0;
    private float attackDuration = 0;
    private float idleDuration = 0;
    private Transform nameTagTransform;
    private Vector3 excursionSpeed = Vector3.zero;
    public MonsterHandle(MonsterModule _module, Transform _root, int _id)
    {
        allHp = hp = 300;
        Module = _module;
        Root = _root;
        id = _id;
        moveController = Root.GetComponent<CharacterController>();
        WeaponObject = AssetHelp.FindChildObject("wuqi", Root, "").gameObject;
        nameTagTransform = AssetHelp.FindChildObject("NameTag", Root, "");
        ClothesObject = AssetHelp.FindChildObject("clothes", Root, "").gameObject;
        targetAvatar = AppInterface.AvatarModule.IOwner;
        defaultPos = Root.position;
        tFindRadius = FindRadius;
        setAnimation();
        setAction();
        state = MonsterState.Stand;
    }
    public void Update()
    {
        process();
        excursionEffect();
    }
    public void FixedUpdate()
    {

    }
    private MovementType direction = MovementType.Right;
    public MovementType Direction
    {
        set
        {
            if (direction != value && value != MovementType.None)
            {
                direction = value;
                if (direction == MovementType.Right) Root.eulerAngles = rightAngle;
                else Root.eulerAngles = leftAngle;
            }
        }
        get
        {
            return direction;
        }
    }
    private void process()
    {
        if (state == MonsterState.Dead) return;
        switch (state)
        {
            #region Stand
            case MonsterState.Stand:
                {
                    distance = Mathf.Abs(targetAvatar.Position.z - Root.position.z);
                    if (!goBack && distance <= tFindRadius)
                    {
                        liveChange(true);
                        tFindRadius = FindRadius;
                        if (targetAvatar.Position.z > Root.position.z) Direction = MovementType.Right;
                        else Direction = MovementType.Left;

                        if (distance <= AttackRadius)
                        {
                            CrossAnimation(AnimationSet.AttackIdle, .3f);

                            //攻击间隔
                            attackDuration -= InputManager.DeltaTime;
                            if (attackDuration <= 0)
                            {
                                attackDuration = AttackInterval;
                                attack();
                            }
                        }
                        else
                        {
                            lastZ = Root.position.z;
                            walk();

                            if (Mathf.Abs(lastZ - Root.position.z) < .01f)
                            {
                                goBack = true;
                                tFindRadius = Mathf.Abs(defaultPos.z - Root.position.z);
                            }
                        }
                    }
                    else
                    {
                        liveChange(false);
                        if (Mathf.Abs(defaultPos.z - Root.transform.position.z) < .1f)
                        {
                            if (hp < allHp)//血回满
                            {
                                float change = allHp - hp;
                                hp = allHp;
                                HpChange(this, allHp - hp);
                            }

                            doIdle();
                            goBack = false;
                        }
                        else
                        {
                            if (defaultPos.z > Root.position.z) Direction = MovementType.Right;
                            else Direction = MovementType.Left;

                            walk();
                        }
                    }
                    break;
                }
            #endregion
            #region On Beat State
            case MonsterState.BasicBeat:
                {
                    beatDuration += InputManager.DeltaTime;
                    if (beatDuration >= beatTimer && grounded)
                    {
                        beatDuration = 0;
                        state = MonsterState.Stand;
                    }
                    break;
                }
            case MonsterState.Collapse:
                {
                    beatDuration += InputManager.DeltaTime;
                    if (beatDuration >= beatTimer && grounded)
                    {
                        beatDuration = 0;
                        if (hp > 0)
                        {
                            beatTimer = Root.animation[AnimationSet.StandUp].length / Root.animation[AnimationSet.StandUp].speed;
                            CrossAnimation(AnimationSet.StandUp, 0);
                            state = MonsterState.StandUp;
                        }
                    }
                    break;
                }
            case MonsterState.StandUp:
                {
                    beatDuration += InputManager.DeltaTime;
                    if (beatDuration >= beatTimer && grounded)
                    {
                        beatDuration = 0;
                        state = MonsterState.Stand;
                    }
                    break;
                }
            #endregion
            #region Dead Ready
            case MonsterState.DeadReady:
                {
                    doDead();
                    deadDuration += InputManager.DeltaTime;
                    if (deadDuration >= flickerWait)
                    {
                        if (flickerTotal >= flickerCount / 2)
                        {
                            if (flickerTotal % 2 == 0) ClothesObject.renderer.enabled = false;
                            else ClothesObject.renderer.enabled = true;
                        }
                        flickerTotal++;
                        deadDuration = 0;
                    }
                    if (flickerTotal > flickerCount)
                    {
                        liveChange(false);
                        state = MonsterState.Dead;
                        GameObject.Destroy(Root.gameObject);
                    }
                    break;
                }
            #endregion
        }
        if (gravity) doGravity();
    }
    private bool excursionJump = false;
    private void excursionEffect()
    {
        if (excursion.x > 0 || excursion.y > 0)
        {
            if (excursion.y > 0)
            {
                gravitySpeed = excursion.y;
                excursionJump = true;
                excursion.y = 0;
            }
            if (excursionJump)
            {
                excursionSpeed.z = -excursion.x;
            }
            else
            {
                if (excursion.x > 0)
                {
                    excursionSpeed.z = -excursion.x;
                    excursion.x -= Friction;
                }
                else excursionSpeed.z = 0;
            }
            //Debug.Log(excursion.x);
            excursionSpeed = Root.TransformDirection(excursionSpeed);
            moveController.Move(excursionSpeed * InputManager.DeltaTime * 30);
        }
    }
    private string lastAnimation = string.Empty;
    
    private void setAnimation()
    {
        AnimationSet = new MonsterAnimationSet();
        Root.animation[AnimationSet.Attack].wrapMode = WrapMode.Once;
        Root.animation[AnimationSet.Attack].layer = 1;
        if (Root.animation.GetClip(AnimationSet.AttackIdle) == null)
        {
            AnimationSet.AttackIdle = AnimationSet.Idle0;
        }
        else
        {
            Root.animation[AnimationSet.AttackIdle].wrapMode = WrapMode.Loop;
        }

        Root.animation[AnimationSet.OnBeat].speed = .5f;
        Root.animation[AnimationSet.OnBeat].wrapMode = WrapMode.Once;
        Root.animation[AnimationSet.OnBeat].layer = 2;
        Root.animation[AnimationSet.OnBeatCollapse].wrapMode = WrapMode.Once;
        Root.animation[AnimationSet.OnBeatCollapse].layer = 2;
        Root.animation[AnimationSet.StandUp].wrapMode = WrapMode.Once;
        Root.animation[AnimationSet.StandUp].layer = 2;

        Root.animation[AnimationSet.Walk].wrapMode = WrapMode.Loop;
        Root.animation[AnimationSet.Idle0].wrapMode = WrapMode.Loop;
        Root.animation[AnimationSet.Idle1].wrapMode = WrapMode.Loop;
    }
    private void setAction()
    {
        if (Root.name.IndexOf("hamajing") > -1)
        {
            ActionList = new ActionParameter[] { 
                new ActionParameter("PigAttack", AnimationSet.Attack, true, 0),
                new ActionParameter("dazhao", AnimationSet.BossSkill, true, 0)
            };
            WalkSpeed = 2;
            Root.animation[AnimationSet.OnBeat].speed = 1;
        }
        else
        {
            ActionList = new ActionParameter[] { new ActionParameter("PigAttack", AnimationSet.Attack, true, 0) };
        }
    }
    private bool doDeadProcess = true;
    private void doDead()
    {
        if (doDeadProcess)
        {
            AppInterface.ActionModule.AddSoul(Root.transform.position);
            doDeadProcess = false;
            Root.animation.Stop();
            CrossAnimation(AnimationSet.OnBeatCollapse, .2f);
        }
    }
    private void doIdle()
    {
        //播放2个 idle 动画
        idleDuration += InputManager.DeltaTime;
        if (idleDuration > 10.0f)
        {
            CrossAnimation(AnimationSet.Idle1, .3f);
            if (idleDuration > 20.0f)
            {
                idleDuration = 0;
            }
        }
        else
        {
            CrossAnimation(AnimationSet.Idle0, .3f);
        }
    }
    private float gravitySpeed = 0;
    private bool grounded = false;
    private void doGravity()
    {
        gravitySpeed -= 4 * InputManager.DeltaTime;
        grounded = (moveController.Move(Vector3.up * gravitySpeed) & CollisionFlags.CollidedBelow) != 0;
        if (grounded)
        {
            gravitySpeed = 0;
            if (excursionJump)
            {
                excursionJump = false;
                excursion.x = 0;
            }
        }
    }
    private void walk()
    {
        speed.z = WalkSpeed;
        tSpeed = Root.TransformDirection(speed * InputManager.DeltaTime);
        moveController.Move(tSpeed);
        CrossAnimation(AnimationSet.Walk, .3f);
    }
    public void CrossAnimation(string animationName, float time)
    {
        if (string.Compare(animationName, lastAnimation) != 0)
        {
            lastAnimation = animationName;
            //Debug.Log("animationName:" + animationName + "," + Root.animation[animationName].wrapMode + "," + Root.animation[animationName].layer);
            Root.animation.CrossFade(animationName, time);
            //Root.animation.CrossFade(animationName, (animationName.IndexOf(AnimationSet.Idle0) > -1 || animationName.IndexOf(AnimationSet.Walk) > -1) ? .3f : .03f);
        }
    }
    private float beatDuration = 0;
    private float beatTimer = 0;
    private void onBeat(ActionBase ation)
    {
        if(doExcursion) excursion = ation.Excursion;
        //attackDuration = AllackInterval;

        beatDuration = 0;
        switch(ation.Beat)
        {
            case OnBeatDefine.Basic:
                {
                    beatTimer = Root.animation[AnimationSet.OnBeat].length / Root.animation[AnimationSet.OnBeat].speed;
                    CrossAnimation(AnimationSet.OnBeat, .1f);
                    state = MonsterState.BasicBeat;
                    break;
                }
            case OnBeatDefine.Collapse:
                {
                    Root.animation.Stop();
                    beatTimer = Root.animation[AnimationSet.OnBeatCollapse].length / Root.animation[AnimationSet.OnBeatCollapse].speed;
                    CrossAnimation(AnimationSet.OnBeatCollapse, .1f);
                    state = MonsterState.Collapse;
                    break;
                }
        }
    }
    private void attack()
    {
        if (CurrentAction == null || CurrentAction.End)
        {
            int index = 0;
            if (ActionList.Length > 1)
            {
                index = 1;
            }
            ActionParameter para = ActionList[index];
            if (Root.animation.GetClip(para.AnimationName) != null)
            {
                CurrentAction = ActionConfig.GetAction(para) as MonsterAction;
                CurrentAction.Animation = Root.animation[para.AnimationName];

                CurrentAction.Handle = this;
                CurrentAction.Start();
            }
        }
        
    }
    private void liveChange(bool live)
    {
        if (Live != live)
        {
            Live = live;
            if (Live) Module.AddTolive(this);
            else Module.DeleteFromlive(this);
        }
    }
    #region IUnit Members
    private int allHp = 0;
    public int AllHp
    {
        get { return allHp; }
    }

    public Collider Collider
    {
        get { return Root.collider; }
    }

    public virtual void DoAction(ushort actionId, bool net)
    {
        throw new NotImplementedException();
    }

    public Transform HeadTransform
    {
        get { throw new NotImplementedException(); }
    }
    private int hp = 0;
    public int Hp
    {
        get { return hp; }
    }
    private int id = 0;
    public int Id
    {
        get { return id; }
    }

    public virtual string Name
    {
        get { throw new NotImplementedException(); }
    }

    public Transform NameTagTransform
    {
        get { return nameTagTransform; }
    }

    public void OnBeat(ActionBase _ation, int _hp, IUnit _from, bool _net)
    {
        if (state == MonsterState.Dead || state == MonsterState.DeadReady) return;
        onBeat(_ation);
        AppInterface.GUIModule.ShowScore(nameTagTransform, _hp);
        hp += _hp;
        if (hp < 0) hp = 0;
        HpChange(this as IUnit, _hp);
        if (hp <= 0)
        {
            state = MonsterState.DeadReady;
        }
    }

    public event Action<IUnit, IUnit> OnDead;
    public void ToDead(IUnit to, IUnit from)
    {
        if (OnDead != null) OnDead(to, from);
    }

    public event PositionChangeHandler OnPositionChange;

    public Vector3 Position
    {
        get { return Root.position; }
    }

    public Collider Weapon
    {
        get { return WeaponObject.collider; }
    }

    public void HpChange(IUnit handle, int tHp)
    {
        if (OnHpChange != null) OnHpChange(handle, tHp);
    }
    public event Action<IUnit, int> OnHpChange;

    public bool Dead
    {
        get { return state == MonsterState.Dead; }
    }

    private Vector2 excursion = Vector2.zero;
    public Vector2 Excursion
    {
        get { return excursion; }
    }

    public float Friction
    {
        get { return .1f; }
    }
    private bool gravity = true;
    public bool Gravity
    {
        get { return gravity; }
        set { gravity = value; }
    }

    public CharacterController Controller
    {
        get { return moveController; }
    }
    private bool doExcursion = true;
    public bool DoExcursion
    {
        get { return doExcursion; }
        set { doExcursion = value; }
    }

    #endregion

    #region IMonsterHandle Members

    public float FindRadius
    {
        get { return findRadius; }
        set { findRadius = value; }
    }

    public float AttackRadius
    {
        get { return attackRadius; }
        set { attackRadius = value; }
    }

    public float AttackInterval
    {
        get { return attackInterval; }
        set { attackInterval = value; }
    }

    public float WalkSpeed
    {
        get { return walkSpeed; }
        set { walkSpeed = value; }
    }

    private MonsterState state = MonsterState.None;
    public MonsterState State
    {
        get { return state; }
        set { state = value; }
    }

    #endregion
}

